using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Windows;

namespace ReactiveLang
{
    // using Linq;
    using Util;

    public class ReactiveHost: IDisposable
    {
        ~ReactiveHost()
        {
            Dispose(false);
        }
        public void Dispose()
        {
            Dispose(true);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
                GC.SuppressFinalize(this);
            foreach(var call in _handles.ToList())
                call.Dispose();
            _handles.Clear();
        }

        LinkedList<ReactiveHandle> _handles = new LinkedList<ReactiveHandle>();

        internal IDisposable AddHandle(ReactiveHandle handle)
        {
            Contract.Requires<ArgumentNullException>(handle != null, "handle");
            Contract.Ensures(Contract.Result<IDisposable>() != null);
            var node = _handles.AddLast(handle);
            return Disposable.Create(() => _handles.Remove(node));
        }

        public ReactiveHandle<T> Add<T>(IExpression<T> expression, bool enable = true)
        {
            Contract.Requires<ArgumentNullException>(expression != null, "expression");
            Contract.Ensures(Contract.Result<ReactiveHandle>() != null);
            Contract.Ensures(Contract.Result<ReactiveHandle>().Enabled == enable);
            var handle = new ReactiveHandle<T>(this, expression);
            if (enable)
                handle.Enabled = true;
            return handle;
        }
        public ReactiveHandle<T> Add<T>(IStatement<T> stmt, bool enable = true)
        {
            return Add(Expression.Call(stmt), enable);
        }

        public event EventHandler<ReactiveUnhandledExceptionEventArgs> UnhandledException;
        internal void OnException(ReactiveUnhandledExceptionEventArgs e)
        {
            var handler = UnhandledException;
            if (handler != null)
                handler(this, e);
        }
    }
}